package com.example.gitnb.module.issue; import android.content.Intent; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.net.Uri; import android.os.Bundle; import android.support.design.widget.AppBarLayout; import android.support.design.widget.CollapsingToolbarLayout; import android.support.design.widget.Snackbar; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import android.util.Log; import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.WindowManager; import android.view.animation.OvershootInterpolator; import android.widget.EditText; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.PopupWindow; import android.widget.TextView; import com.example.gitnb.R; import com.example.gitnb.app.BaseSwipeActivity; import com.example.gitnb.model.CommentRequest; import com.example.gitnb.model.GithubComment; import com.example.gitnb.model.Issue; import com.example.gitnb.model.IssueRequest; import com.example.gitnb.model.IssueState; import com.example.gitnb.model.Repository; import com.example.gitnb.module.custom.processor.BlurPostprocessor; import com.example.gitnb.module.search.HotReposFragment; import com.example.gitnb.module.search.HotUserFragment; import com.example.gitnb.module.user.UserDetailActivity; import com.example.gitnb.utils.CurrentUser; import com.example.gitnb.utils.Utils; import com.facebook.drawee.backends.pipeline.Fresco; import com.facebook.drawee.backends.pipeline.PipelineDraweeController; import com.facebook.drawee.view.SimpleDraweeView; import com.facebook.imagepipeline.request.ImageRequest; import com.facebook.imagepipeline.request.ImageRequestBuilder; import java.util.ArrayList; import jp.wasabeef.recyclerview.adapters.ScaleInAnimationAdapter; import jp.wasabeef.recyclerview.adapters.SlideInBottomAnimationAdapter; import retrofit.Response; import rx.Observer; import rx.android.schedulers.AndroidSchedulers; import rx.schedulers.Schedulers; public class IssueDetailActivity extends BaseSwipeActivity implements IssueCommentListAdapter.OnItemClickListener{ private String TAG = IssueDetailActivity.class.getName(); public static String ISSUE_URL = "issue_url"; public static String ISSUE = "issue"; private CollapsingToolbarLayout mCollapsingToolbarLayout; private IssueCommentListAdapter adapter; private SimpleDraweeView user_background; private SimpleDraweeView user_avatar; private RecyclerView recyclerView; private PopupWindow popupWindow; private TextView issue_title; private boolean isLoadingMore; private Repository repos; private String issueUrl; private int page = 1; private Issue issue; private Observer<ArrayList<GithubComment>> observer = new Observer<ArrayList<GithubComment>>() { @Override public void onNext(ArrayList<GithubComment> result) { onOK(result); } @Override public void onCompleted() { } @Override public void onError(Throwable error) { endError(error.getMessage()); } }; protected void setTitle(TextView view){ if(issue != null && !issue.title.isEmpty()){ view.setText(issue.title); }else{ view.setText("NULL"); } view.setSelected(true); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Intent intent = getIntent(); issueUrl = intent.getStringExtra(ISSUE_URL); issue = intent.getParcelableExtra(ISSUE); repos = intent.getParcelableExtra(HotReposFragment.REPOS); setContentView(R.layout.activity_issue_detail); recyclerView = (RecyclerView) findViewById(R.id.recyclerView); recyclerView.setLayoutManager(new LinearLayoutManager(this)); mCollapsingToolbarLayout = (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar_layout); user_background = (SimpleDraweeView)findViewById(R.id.user_background); user_avatar = (SimpleDraweeView)findViewById(R.id.user_avatar); issue_title = (TextView)findViewById(R.id.issue_title); AppBarLayout appBarLayout = (AppBarLayout) findViewById(R.id.appBarLayout); appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() { @Override public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { //The Refresh must be only active when the offset is zero : getSwipeRefreshLayout().setEnabled(verticalOffset == 0); float alpha = Math.abs(verticalOffset / (appBarLayout.getHeight() - getToolbar().getHeight() - getResources().getDimension(R.dimen.system_ui_height))); if(user_avatar != null) user_avatar.setAlpha(1 - alpha); if(issue_title != null) issue_title.setAlpha(1 - alpha); if(alpha>0.8f){ mCollapsingToolbarLayout.setTitle(issue.title); } else{ mCollapsingToolbarLayout.setTitle(""); } } }); } private void initUserBackground(){ invalidateOptionsMenu(); issue_title.setText(issue.title); user_avatar.setImageURI(Uri.parse(issue.user.getAvatar_url())); user_avatar.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (issue.user != null) { Intent intent = new Intent(IssueDetailActivity.this, UserDetailActivity.class); Bundle bundle = new Bundle(); bundle.putParcelable(HotUserFragment.USER, issue.user); intent.putExtras(bundle); startActivity(intent); } } }); ImageRequest request = ImageRequestBuilder.newBuilderWithSource(Uri.parse(issue.user.getAvatar_url())) .setPostprocessor(new BlurPostprocessor(IssueDetailActivity.this)) .build(); PipelineDraweeController controller = (PipelineDraweeController) Fresco.newDraweeControllerBuilder() .setImageRequest(request) .setOldController(user_background.getController()) .build(); user_background.setController(controller); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.repos_detail_menu, menu); // shareActionProvider = (ShareActionProvider) item.getActionProvider(); //返回true,显示菜单 return true; } @Override public boolean onPrepareOptionsMenu(Menu menu) { if(issue != null) { if (issue.state.toString().equals("open")) { if (issue.user.getId() == CurrentUser.getInstance().getMe().getId()) { menu.findItem(R.id.menu_item_edit_issue).setVisible(true); } if (repos.getOwner().getId() == CurrentUser.getInstance().getMe().getId() || issue.user.getId() == CurrentUser.getInstance().getMe().getId()) { menu.findItem(R.id.menu_item_close_issue).setVisible(true); } menu.findItem(R.id.menu_item_add_comment).setVisible(true); } } return super.onPrepareOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_item_add_comment: showAddCommentPop(recyclerView); break; case R.id.menu_item_edit_issue: showEditIssuePop(recyclerView); break; case R.id.menu_item_close_issue: closeIssue(); break; } return super.onOptionsItemSelected(item); } @Override public void onItemClick(View v, final int position) { switch (v.getId()) { case R.id.operation: showOperationPop(recyclerView, position); break; case R.id.edit: showEditCommentPop(recyclerView, position); break; case R.id.delete: showDeletePop(v, position); break; case R.id.user_avatar: if (repos.getOwner() != null) { Intent intent = new Intent(IssueDetailActivity.this, UserDetailActivity.class); Bundle bundle = new Bundle(); bundle.putParcelable(HotUserFragment.USER, adapter.getItem(position).user); intent.putExtras(bundle); startActivity(intent); } break; } } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if(keyCode == KeyEvent.KEYCODE_MENU) { return true; } else { return super.onKeyDown(keyCode, event); } } @Override public void onBackPressed() { if (popupWindow != null && popupWindow.isShowing()) { popupWindow.dismiss(); }else{ super.onBackPressed(); } } @Override public void toolBarColorChange(int color){ //mCollapsingToolbarLayout.setContentScrimColor(color); } @Override protected void startRefresh(){ super.startRefresh(); if(!TextUtils.isEmpty(issueUrl)){ getIssueDetail(); } else if(issue != null){ initUserBackground(); getIssueComments(); } } @Override protected void endRefresh(){ super.endRefresh(); isLoadingMore = false; } @Override protected void endError(String Message){ super.endError(Message); isLoadingMore = false; } private void updateAdapter(ArrayList<GithubComment> ts){ if(adapter == null) { adapter = new IssueCommentListAdapter(this, repos, issue); adapter.update(ts); adapter.setOnItemClickListener(this); adapter.setOnLoadMoreClickListener(new IssueCommentListAdapter.OnItemClickListener() { @Override public void onItemClick(View view, int position) { if(isLoadingMore){ Log.d(TAG,"ignore manually update!"); } else{ page++; isLoadingMore = true; startRefresh(); } } }); ScaleInAnimationAdapter scaleInAdapter = new ScaleInAnimationAdapter(adapter); SlideInBottomAnimationAdapter slideInAdapter = new SlideInBottomAnimationAdapter(scaleInAdapter); slideInAdapter.setDuration(300); slideInAdapter.setInterpolator(new OvershootInterpolator()); recyclerView.setAdapter(slideInAdapter); recyclerView.scheduleLayoutAnimation(); } else{ if(page == 1){ adapter.update(ts); recyclerView.scrollToPosition(0); } else{ isLoadingMore = false; adapter.insertAtBack(ts); } } } public void onOK(ArrayList<GithubComment> ts) { updateAdapter(ts); endRefresh(); } private void showDeleteSnackbar(final int position){ Snackbar snackBar = Snackbar.make(recyclerView, R.string.delete_comment_tips, Snackbar.LENGTH_LONG); snackBar.setAction("YES", new View.OnClickListener() { @Override public void onClick(View v) { deleteComment(adapter.getItem(position).id, position); } }); View view = snackBar.getView(); view.setBackgroundColor(getResources().getColor(R.color.orange_yellow)); TextView tv = (TextView) view.findViewById(R.id.snackbar_text); tv.setTextColor(Color.WHITE); snackBar.setActionTextColor(Color.BLACK); final WindowManager.LayoutParams wlBackground = getWindow().getAttributes(); wlBackground.alpha = 0.75f; getWindow().setAttributes(wlBackground); snackBar.setCallback(new Snackbar.Callback() { @Override public void onDismissed(Snackbar snackbar, int event) { wlBackground.alpha = 1.0f; getWindow().setAttributes(wlBackground); super.onDismissed(snackbar, event); } }); snackBar.show(); } private void showOperationPop(View parent, final int position){ View contentView = LayoutInflater.from(this).inflate(R.layout.comment_operation_popup_layout, null, false); final TextView edit = (TextView)contentView.findViewById(R.id.edit); final TextView delete = (TextView)contentView.findViewById(R.id.delete); edit.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (popupWindow != null && popupWindow.isShowing()) { popupWindow.dismiss(); } showEditCommentPop(recyclerView, position); } }); delete.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (popupWindow != null && popupWindow.isShowing()) { popupWindow.dismiss(); } showDeleteSnackbar(position); } }); showCommentPop(parent, contentView); } private void showEditIssuePop(View parent){ View contentView = LayoutInflater.from(this).inflate(R.layout.add_issue_popup_layout, null, false); final EditText title = (EditText)contentView.findViewById(R.id.title); final EditText comment = (EditText)contentView.findViewById(R.id.comment); title.setText(issue.title); comment.setText(issue.body); TextView send = (TextView) contentView.findViewById(R.id.send); send.setText("Edit"); send.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { editIssue(title.getText().toString(), comment.getText().toString()); if (popupWindow != null && popupWindow.isShowing()) { popupWindow.dismiss(); } } }); showCommentPop(parent, contentView); } private void showAddCommentPop(View parent) { View contentView = LayoutInflater.from(this).inflate(R.layout.add_comment_popup_layout, null, false); final EditText comment = (EditText) contentView.findViewById(R.id.comment); TextView send = (TextView) contentView.findViewById(R.id.send); send.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { addComment(comment.getText().toString()); if (popupWindow != null && popupWindow.isShowing()) { popupWindow.dismiss(); } } }); showCommentPop(parent, contentView); } private void showEditCommentPop(View parent, final int position) { View contentView = LayoutInflater.from(this).inflate(R.layout.add_comment_popup_layout, null, false); final EditText comment = (EditText) contentView.findViewById(R.id.comment); comment.setText(adapter.getItem(position).body); TextView send = (TextView) contentView.findViewById(R.id.send); send.setText("Edit"); send.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { adapter.getItem(position).body = comment.getText().toString(); adapter.notifyItemChanged(position); editComment(adapter.getItem(position).id, comment.getText().toString()); if (popupWindow != null && popupWindow.isShowing()) { popupWindow.dismiss(); } } }); showCommentPop(parent, contentView); } private void showCommentPop(View parent, View contentView){ ImageView back = (ImageView)contentView.findViewById(R.id.cancel); if(back != null) { back.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (popupWindow != null && popupWindow.isShowing()) { popupWindow.dismiss(); } } }); } getCommentPop(contentView, LinearLayout.LayoutParams.MATCH_PARENT); popupWindow.showAtLocation(parent, Gravity.BOTTOM, 0, 0); } private void showDeletePop(View view, final int position){ View contentView = LayoutInflater.from(this).inflate(R.layout.delete_popup_layout, null, false); final TextView deleteButton = (TextView)contentView.findViewById(R.id.delete); deleteButton.setText("Delete the comment?"); deleteButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { deleteComment(adapter.getItem(position).id, position); if (popupWindow != null && popupWindow.isShowing()) { popupWindow.dismiss(); } } }); getCommentPop(contentView, LinearLayout.LayoutParams.WRAP_CONTENT); int[] location = new int[2] ; //view.getLocationInWindow(location); //获取在当前窗口内的绝对坐标 view.getLocationOnScreen(location); WindowManager wm = this.getWindowManager(); int height = wm.getDefaultDisplay().getHeight(); int j = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); contentView.measure(j,j); if(height-location[1]-view.getHeight()>contentView.getMeasuredHeight()) { //popupWindow.showAsDropDown(view); popupWindow.showAtLocation(view,Gravity.NO_GRAVITY, location[0]-contentView.getMeasuredWidth(), location[1]+view.getHeight()); } else{ popupWindow.showAtLocation(view,Gravity.NO_GRAVITY, location[0]-contentView.getMeasuredWidth(), location[1]-contentView.getMeasuredHeight()); } } private void getCommentPop(View contentView, int width){ popupWindow = new PopupWindow(contentView, width, LinearLayout.LayoutParams.WRAP_CONTENT); popupWindow.setFocusable(true); popupWindow.setBackgroundDrawable(new ColorDrawable(0x00000000)); final WindowManager.LayoutParams wlBackground = getWindow().getAttributes(); wlBackground.alpha = 0.75f; getWindow().setAttributes(wlBackground); popupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() { @Override public void onDismiss() { wlBackground.alpha = 1.0f; getWindow().setAttributes(wlBackground); } }); popupWindow.setSoftInputMode(PopupWindow.INPUT_METHOD_NEEDED); popupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); popupWindow.setAnimationStyle(R.style.anim_popup_bottombar); } private void getIssueDetail(){ if(issueUrl != null && issueUrl.lastIndexOf("/") > 0) { String idStr = issueUrl.substring(issueUrl.lastIndexOf("/")+1); getApiService().detailIssue(repos.getOwner().getLogin(), repos.getName(), Integer.parseInt(idStr)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<Issue>() { @Override public void onNext(Issue result) { issue = result; initUserBackground(); getIssueComments(); } @Override public void onCompleted() { } @Override public void onError(Throwable error) { endError(error.getMessage()); } }); } } private void getIssueComments(){ getApiService().comments(repos.getOwner().getLogin(), repos.getName(), issue.number, page) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(observer); } private void editIssue(String title, String body){ IssueRequest issueRequest = new IssueRequest(); issueRequest.title = title; issueRequest.body = body; issue.title = title; issue.body = body; adapter.notifyItemChanged(0); getApiService().editIssue(repos.getOwner().getLogin(), repos.getName(), issue.number, issueRequest) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<Issue>() { @Override public void onNext(Issue result) { startRefresh(); } @Override public void onCompleted() { } @Override public void onError(Throwable error) { endError(error.getMessage()); } }); } private void closeIssue(){ IssueRequest issueRequest = new IssueRequest(); issueRequest.state = IssueState.closed; getApiService().closeIssue(repos.getOwner().getLogin(), repos.getName(), issue.number, issueRequest) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<Issue>() { @Override public void onNext(Issue result) { startRefresh(); } @Override public void onCompleted() { } @Override public void onError(Throwable error) { endError(error.getMessage()); } }); } private void editComment(String id, String body){ CommentRequest commentRequest = new CommentRequest(body); getApiService().editComment(repos.getOwner().getLogin(), repos.getName(), id, commentRequest) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<GithubComment>() { @Override public void onNext(GithubComment result) { getIssueComments(); } @Override public void onCompleted() { } @Override public void onError(Throwable error) { endError(error.getMessage()); } }); } private void addComment(String body){ GithubComment githubComment = new GithubComment(); githubComment.body = body; githubComment.user = CurrentUser.getInstance().getMe(); githubComment.updated_at = Utils.now(); adapter.add(githubComment); recyclerView.smoothScrollToPosition(adapter.getItemCount()); getApiService().addComment(repos.getOwner().getLogin(), repos.getName(), issue.number, githubComment) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<GithubComment>() { @Override public void onNext(GithubComment result) { getIssueComments(); } @Override public void onCompleted() { } @Override public void onError(Throwable error) { endError(error.getMessage()); } }); } private void deleteComment(String id, final int position){ adapter.delete(position); getApiService().deleteComment(repos.getOwner().getLogin(), repos.getName(), id) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<Response<GithubComment>>() { @Override public void onNext(Response<GithubComment> result) { getIssueComments(); } @Override public void onCompleted() { } @Override public void onError(Throwable error) { endError(error.getMessage()); } }); } }